/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <devmon/driver_abi.h>
#include <dlfcn.h>
#include <gtest/gtest.h>
#include <test_utilities/test_base.h>

#include "hi183x/hi183x_card.h"
#include "hi183x/hi183x_om.h"
#include "hi183x/hi183x_port.h"

using namespace dev;

namespace drivers {
namespace pcie_nic_card {
namespace hisi {

namespace test {

class hi183x_test_service : public mc::engine::service {
public:
    hi183x_test_service(const std::string& name) : mc::engine::service(name) {
    }
};

class Hi183xAbiTest : public mc::test::TestWithEngine {
public:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service.init();
        m_test_service.start();
        load_driver();
    }

    static void TearDownTestSuite() {
        m_test_service.stop();
        if (m_driver_handle != nullptr) {
            dlclose(m_driver_handle);
            m_driver_handle = nullptr;
        }
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
    }

    void TearDown() override {
    }

    static void load_driver() {
        m_driver_handle = dlopen("./opt/bmc/drivers/libhisi_183x.so", RTLD_LAZY);
        if (m_driver_handle == nullptr) {
            MC_THROW(mc::system_exception, "Failed to load driver: ${error}", ("error", dlerror()));
        }
        register_device_driver_func func = reinterpret_cast<register_device_driver_func>(
            dlsym(m_driver_handle, "register_device_driver"));
        MC_ASSERT_THROW(func, mc::bad_function_call_exception,
                        "Failed to get export_device_driver function: ${error}",
                        ("error", dlerror()));

        device_driver_t* devices       = nullptr;
        uint8_t          devices_count = 0;
        status_t         ret           = func(&devices, &devices_count);
        MC_ASSERT_THROW(ret == STATUS_OK, mc::bad_function_call_exception,
                        "Failed to get device driver manager: ${error}", ("error", ret));

        m_devices.clear();
        m_devices.reserve(devices_count);
        for (uint8_t i = 0; i < devices_count; i++) {
            auto device_driver = std::make_shared<device_driver_t>(devices[i]);
            m_devices.emplace(device_driver->device_name, device_driver);
        }
    }

    mc::dict create_test_connector(uint8_t system_id, uint8_t position, uint8_t slot) {
        return mc::dict{{"SystemId", system_id}, {"Position", position}, {"Slot", slot}};
    }

    static hi183x_test_service                                               m_test_service;
    static std::unordered_map<std::string, std::shared_ptr<device_driver_t>> m_devices;
    static void*                                                             m_driver_handle;
};

hi183x_test_service Hi183xAbiTest::m_test_service{"bmc.kepler.test_hi183x"};
std::unordered_map<std::string, std::shared_ptr<device_driver_t>> Hi183xAbiTest::m_devices;
void* Hi183xAbiTest::m_driver_handle = nullptr;

// ========================= 驱动注册功能测试 =========================

TEST_F(Hi183xAbiTest, register_device_driver_success) {
    // 验证驱动注册成功，并且包含预期的设备类型
    EXPECT_EQ(m_devices.size(), 3);
    EXPECT_TRUE(m_devices.find("PCIeNicCard") != m_devices.end());
    EXPECT_TRUE(m_devices.find("NetworkPort") != m_devices.end());
    EXPECT_TRUE(m_devices.find("OpticalModule") != m_devices.end());
}

TEST_F(Hi183xAbiTest, device_driver_structure_validation) {
    // 验证每个设备驱动的结构完整性
    for (const auto& [device_name, device_driver] : m_devices) {
        EXPECT_FALSE(std::string(device_driver->device_name).empty());
        EXPECT_TRUE(device_driver->ctor != nullptr);
        EXPECT_TRUE(device_driver->init != nullptr);
        EXPECT_TRUE(device_driver->start != nullptr);
        EXPECT_TRUE(device_driver->stop != nullptr);
    }
}

// ========================= PCIeNicCard设备测试 =========================

TEST_F(Hi183xAbiTest, create_hi183x_card_success) {
    auto device_driver = m_devices["PCIeNicCard"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_card");
    ASSERT_TRUE(device != nullptr);
}

TEST_F(Hi183xAbiTest, create_hi183x_card_null_service) {
    auto device_driver = m_devices["PCIeNicCard"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空服务指针应该返回nullptr
    auto device = device_driver->ctor(nullptr, "hi183x_card");
    EXPECT_EQ(device, nullptr);
}

TEST_F(Hi183xAbiTest, init_hi183x_card_null_params) {
    auto device_driver = m_devices["PCIeNicCard"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_card_null_test");
    ASSERT_TRUE(device != nullptr);

    // 测试空参数初始化
    status_t ret = device_driver->init(device, nullptr, nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

// ========================= NetworkPort设备测试 =========================

TEST_F(Hi183xAbiTest, create_hi183x_port_success) {
    auto device_driver = m_devices["NetworkPort"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_port");
    ASSERT_TRUE(device != nullptr);
}

TEST_F(Hi183xAbiTest, create_hi183x_port_null_service) {
    auto device_driver = m_devices["NetworkPort"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空服务指针应该返回nullptr
    auto device = device_driver->ctor(nullptr, "hi183x_port");
    EXPECT_EQ(device, nullptr);
}

TEST_F(Hi183xAbiTest, init_hi183x_port_null_params) {
    auto device_driver = m_devices["NetworkPort"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_port_null_test");
    ASSERT_TRUE(device != nullptr);

    // 测试空参数初始化
    status_t ret = device_driver->init(device, nullptr, nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

// ========================= OpticalModule设备测试 =========================

TEST_F(Hi183xAbiTest, create_hi183x_optical_module_success) {
    auto device_driver = m_devices["OpticalModule"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_optical_module");
    ASSERT_TRUE(device != nullptr);
}

TEST_F(Hi183xAbiTest, create_hi183x_optical_module_null_service) {
    auto device_driver = m_devices["OpticalModule"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空服务指针应该返回nullptr
    auto device = device_driver->ctor(nullptr, "hi183x_optical_module");
    EXPECT_EQ(device, nullptr);
}

TEST_F(Hi183xAbiTest, init_hi183x_optical_module_null_params) {
    auto device_driver = m_devices["OpticalModule"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(&m_test_service, "hi183x_optical_module_null_test");
    ASSERT_TRUE(device != nullptr);

    // 测试空参数初始化
    status_t ret = device_driver->init(device, nullptr, nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

// ========================= 错误处理测试 =========================

TEST_F(Hi183xAbiTest, device_pcienicard_with_null_device) {
    auto device_driver = m_devices["PCIeNicCard"];
    ASSERT_TRUE(device_driver != nullptr);

    void* device = device_driver->ctor(&m_test_service, nullptr);
    EXPECT_EQ(device, nullptr);

    device = device_driver->ctor(nullptr, "hi183x_card_null_params");
    EXPECT_EQ(device, nullptr);

    status_t init_ret = device_driver->init(nullptr, nullptr, nullptr);
    EXPECT_EQ(init_ret, STATUS_ERROR);

    status_t start_ret = device_driver->start(nullptr);
    EXPECT_EQ(start_ret, STATUS_ERROR);

    status_t stop_ret = device_driver->stop(nullptr);
    EXPECT_EQ(stop_ret, STATUS_ERROR);
}

TEST_F(Hi183xAbiTest, device_networkport_with_null_params) {
    auto device_driver = m_devices["NetworkPort"];
    ASSERT_TRUE(device_driver != nullptr);

    void* device = device_driver->ctor(&m_test_service, nullptr);
    EXPECT_EQ(device, nullptr);

    device = device_driver->ctor(nullptr, "hi183x_port_null_params");
    EXPECT_EQ(device, nullptr);

    status_t init_ret = device_driver->init(nullptr, nullptr, nullptr);
    EXPECT_EQ(init_ret, STATUS_ERROR);

    status_t start_ret = device_driver->start(nullptr);
    EXPECT_EQ(start_ret, STATUS_ERROR);

    status_t stop_ret = device_driver->stop(nullptr);
    EXPECT_EQ(stop_ret, STATUS_ERROR);
}

TEST_F(Hi183xAbiTest, device_opticalmodule_with_null_params) {
    auto device_driver = m_devices["OpticalModule"];
    ASSERT_TRUE(device_driver != nullptr);

    void* device = device_driver->ctor(&m_test_service, nullptr);
    EXPECT_EQ(device, nullptr);

    device = device_driver->ctor(nullptr, "hi183x_optical_module_null_params");
    EXPECT_EQ(device, nullptr);

    status_t init_ret = device_driver->init(nullptr, nullptr, nullptr);
    EXPECT_EQ(init_ret, STATUS_ERROR);

    status_t start_ret = device_driver->start(nullptr);
    EXPECT_EQ(start_ret, STATUS_ERROR);

    status_t stop_ret = device_driver->stop(nullptr);
    EXPECT_EQ(stop_ret, STATUS_ERROR);
}

// ========================= 多设备并发测试 =========================

TEST_F(Hi183xAbiTest, multiple_devices_creation) {
    // 测试同时创建多个不同类型的设备
    std::vector<driver_handle_t> pcie_nic_card_devices;
    std::vector<driver_handle_t> network_port_devices;
    std::vector<driver_handle_t> optical_module_devices;

    // 创建多个PCIeNicCard设备
    auto card_driver = m_devices["PCIeNicCard"];
    for (int i = 0; i < 3; ++i) {
        std::string device_name = "hi183x_card_" + std::to_string(i);
        auto        device      = card_driver->ctor(&m_test_service, device_name.c_str());
        ASSERT_TRUE(device != nullptr);
        pcie_nic_card_devices.push_back(device);
    }

    // 创建多个NetworkPort设备
    auto port_driver = m_devices["NetworkPort"];
    for (int i = 0; i < 3; ++i) {
        std::string device_name = "hi183x_port_" + std::to_string(i);
        auto        device      = port_driver->ctor(&m_test_service, device_name.c_str());
        ASSERT_TRUE(device != nullptr);
        network_port_devices.push_back(device);
    }

    // 创建多个OpticalModule设备
    auto om_driver = m_devices["OpticalModule"];
    for (int i = 0; i < 3; ++i) {
        std::string device_name = "hi183x_om_" + std::to_string(i);
        auto        device      = om_driver->ctor(&m_test_service, device_name.c_str());
        ASSERT_TRUE(device != nullptr);
        optical_module_devices.push_back(device);
    }

    EXPECT_EQ(pcie_nic_card_devices.size(), 3);
    EXPECT_EQ(network_port_devices.size(), 3);
    EXPECT_EQ(optical_module_devices.size(), 3);
}

TEST_F(Hi183xAbiTest, hi183x_card_full_lifecycle) {
    auto connector = create_test_connector(1, 1, 1);

    // 创建PCIeNicCard设备
    auto device_driver = m_devices["PCIeNicCard"];
    ASSERT_TRUE(device_driver != nullptr);
    auto card_device =
        static_cast<hi183x_card*>(device_driver->ctor(&m_test_service, "hi183x_card_lifecycle"));
    ASSERT_TRUE(card_device != nullptr);

    card_device->set_object_name("hi183x_card_lifecycle");
    card_device->set_position("1");
    auto card_csr_object =
        mc::mutable_dict{{"bmc.dev.PcieDevice", mc::dict{{"DeviceName", "test_hi183x_card"}}}};

    status_t card_init_ret = device_driver->init(card_device, &card_csr_object, &connector);
    EXPECT_EQ(card_init_ret, STATUS_OK);

    auto port_driver = m_devices["NetworkPort"];
    ASSERT_TRUE(port_driver != nullptr);

    auto port_device =
        static_cast<hi183x_port*>(port_driver->ctor(&m_test_service, "hi183x_port_lifecycle"));
    ASSERT_TRUE(port_device != nullptr);

    port_device->set_object_name("hi183x_port_lifecycle");
    port_device->set_position("1");
    port_device->set_parent(card_device);
    auto port_csr_object = mc::mutable_dict{{"bmc.dev.NetworkPort", mc::dict{{"PortId", 1}}}};

    status_t port_init_ret = port_driver->init(port_device, &port_csr_object, &connector);
    EXPECT_EQ(port_init_ret, STATUS_OK);

    auto om_driver = m_devices["OpticalModule"];
    ASSERT_TRUE(om_driver != nullptr);

    auto om_device = static_cast<hi183x_optical_module*>(
        om_driver->ctor(&m_test_service, "hi183x_optical_module_lifecycle"));
    ASSERT_TRUE(om_device != nullptr);

    om_device->set_object_name("hi183x_optical_module_lifecycle");
    om_device->set_position("1");
    om_device->set_parent(port_device);
    auto om_csr_object = mc::mutable_dict{{"bmc.dev.OpticalModule", mc::dict{}}};

    status_t om_init_ret = om_driver->init(om_device, &om_csr_object, &connector);
    EXPECT_EQ(om_init_ret, STATUS_OK);

    // 启动设备
    status_t card_start_ret = device_driver->start(card_device);
    EXPECT_EQ(card_start_ret, STATUS_OK);
}

} // namespace test
} // namespace hisi
} // namespace pcie_nic_card
} // namespace drivers 